


pub fn xor_sum(buf: &[u8]) -> u8 {
    let mut s = 0;
    for v in buf {
        s = s ^ *v;
    }
    s
}

pub trait Frame {

    fn read_byte(&mut self) -> u8;
    fn read(&mut self, buf: &mut [u8]) -> usize;
    fn is_empty(&self) -> bool;
    fn len(&self) -> usize;
}

pub trait Receiver {
    
    type Frame : Frame;
    
    const FRAME_BYTE_TIMEOUT: u32 = 20;
    const MIN_LEN: u8 = 8;
    
    fn take(&mut self) -> Self::Frame;

    fn poll(&mut self, timeout: u32) -> Option<Self::Frame>;
}

pub struct GenericReceiver<R: Receiver> {
    reader: R,
    frame: R::Frame,
}

#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ReceiverError {
    FrameByteTimeout,
}

impl <R: Receiver> GenericReceiver<R> {

    pub const fn const_new(r: R, frame: R::Frame) -> Self {
        Self { reader: r, frame }
    }

    pub fn read_proto_frame<'a>(&mut self, buf: &'a mut [u8]) -> Result<&'a [u8], ProtoError<ReceiverError>> {
        read_proto_frame(self, buf)
    }
}

impl <R: Receiver> Reader for GenericReceiver<R> {

    type Error = ReceiverError;
    const MIN_LEN: u8 = R::MIN_LEN;

    fn read(&mut self) -> Result<u8, Self::Error> {
        if self.frame.is_empty() {
            self.frame = self.reader.poll(R::FRAME_BYTE_TIMEOUT).ok_or(ReceiverError::FrameByteTimeout)?;
        }
        let v = self.frame.read_byte();
        Ok(v)
    }

    fn read_extract(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
        let mut index = 0;
        let len = buf.len();
        while index < len {
            if self.frame.is_empty() {
                self.frame = self.reader.poll(R::FRAME_BYTE_TIMEOUT).ok_or(ReceiverError::FrameByteTimeout)?;
            }
            let n = self.frame.read(&mut buf[index..]);
            index += n;
        }
        Ok(index)
    }

    fn wait_ready(&mut self) {
        if self.frame.is_empty() {
            self.frame = self.reader.take();
        }
    }
}

pub trait Reader {
    type Error;

    fn read(&mut self) -> Result<u8, Self::Error>;
    fn read_extract(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error>;
    fn wait_ready(&mut self);

    const HEAD0: u8 = 0xE1;
    const HEAD1: u8 = 0x1E;
    const END: u8 = 0xEF;
    const MIN_LEN: u8 = 8;
}

#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ProtoError<E> {
    LengthInvalid,
    BufferOver,
    CheckSum,
    EndInvalid,
    Receiver(E),
}

pub fn read_proto_frame<'a, T: Reader>(
    reader: &mut T,
    buf: &'a mut [u8],
) -> Result<&'a [u8], ProtoError<T::Error>> {
    reader.wait_ready();

    let n = sync(reader)?;
    let len = n - 3;

    if len > buf.len() {
        return Err(ProtoError::BufferOver);
    }

    let pbuf = &mut buf[..len];
    reader.read_extract(pbuf).map_err(ProtoError::Receiver)?;

    let s = xor_sum(&pbuf[..(len - 2)]);
    if s != pbuf[len - 2] {
        return Err(ProtoError::CheckSum);
    }

    if T::END != pbuf[len - 1] {
        return Err(ProtoError::EndInvalid);
    }

    return Ok(pbuf);
}

fn sync<T: Reader>(reader: &mut T) -> Result<usize, ProtoError<T::Error>> {
    let mut flag = false;
    loop {
        let v = reader.read().map_err(ProtoError::Receiver)?;
        if flag && (v == T::HEAD1) {
            break;
        }
        flag = v == T::HEAD0;
    }
    let n = reader.read().map_err(ProtoError::Receiver)?;
    if n < T::MIN_LEN {
        return Err(ProtoError::LengthInvalid);
    }
    Ok(n as usize)
}
